#!/usr/bin/env python
# encoding: utf-8
"""
#-------------------------------------------------------------------#
#                   CONFIDENTIAL --- CUSTOM STUDIOS                 #     
#-------------------------------------------------------------------#
#                                                                   #
#                   @Project Name : Globallawonline                #
#                                                                   #
#                   @File Name    : ExportLaw.py                      #
#                                                                   #
#                   @Programmer   : 李建                            #
#                                                                   #  
#                   @Start Date   : 2021/1/8 15:40                 #
#                                                                   #
#                   @Last Update  : 2021/1/8 15:40                 #
#                                                                   #
#-------------------------------------------------------------------#
# Classes:该类用于上传法律pdf数据到web服务器                                                          #
#                                                                   #
#-------------------------------------------------------------------#
"""
import datetime
import os
from ftplib import FTP

from settings import FILES_DIR, FTPCONN, FTPCONN_JW


class ExportLaw:
    def __init__(self):
        pass

    # def __del__(self):
    #     self.ftp.quit()

    def ftpconnect(self, host, port, username, password):
        """
        一个主动模式的ftp连接
        :param host:
        :param port:
        :param username:
        :param password:
        :return:
        """
        ftp = FTP()
        ftp.encoding = "utf-8"  # 设置ftp支持中文文件名
        ftp.connect(host, port)     # 连接的ftp server和端口
        ftp.login(username, password)   # 连接的用户名和密码
        ftp.set_pasv(False)  # 设置ftp连接为主动模式
        return ftp

    def ftpconnectun(self, host, port, username, password):
        """
        一个被动模式的ftp连接
        :param host:
        :param port:
        :param username:
        :param password:
        :return:
        """
        ftp = FTP()
        ftp.encoding = "utf-8"  # 设置ftp支持中文文件名
        ftp.connect(host, port)
        ftp.login(username, password)
        return ftp

    def __download_file(self, ftp, remotepath, localpath):
        """
        FTP文件下载
        :param ftp: ftp连接
        :param remotepath: FTP服务器上的文件详细地址
        :param localpath: 本地文件的详细地址
        :return: 文件成功下载到本地或者一个错误类型
        """
        bufsize = 1024
        fp = open(localpath, 'wb')
        try:
            ftp.retrbinary('RETR ' + remotepath, fp.write, bufsize)
            ftp.set_debuglevel(0)
            fp.close()
            return True
        except Exception as e:
            print("从%s服务器上下载文件失败:%s" % (ftp.host, str(e)))
            return False

    def __upload_file(self, ftp, remotepath, localpath):
        """
        FTP文件上传
        :param ftp: ftp连接
        :param remotepath: FTP服务器上的文件详细地址
        :param localpath: 本地文件的详细地址
        :return: 文件成功上传到FTP服务器或者一个错误类型
        """
        bufsize = 1024
        fp = open(localpath, 'rb')

        try:
            ftp.storbinary('STOR ' + remotepath, fp, bufsize)
            ftp.set_debuglevel(0)
            fp.close()
            return True
        except Exception as e:
            print("上传文件到%s服务器失败:%s" % (ftp.host, str(e)))
            return False

    def __export_faillaw(self, ftp, file):
        """
        重新上传上传失败的文件
        :param ftp: ftp连接
        :param file: 上传失败目录
        :return:
        """
        with open(file, 'r+', encoding='utf-8') as f:  # 读取上次未上传成功的文件重新上传
            for linen in f:  # 按行读取文件
                line = linen.replace('\n', '')
                paths = line.split(', ')
                ftp_file_path = paths[0]
                path = paths[1]
                upresult = self.__upload_file(ftp,ftp_file_path, path)  # 上传之前上传失败的文件
                if upresult:
                    continue
                else:  # 未上传成功的继续写入上传失败记录
                    f.write(linen)

    def __down_faildata(self, ftp, file):
        """
        重新从香港服务器下载下载失败的文件
        :param ftp: ftp连接
        :param file: 下载失败目录
        :return:
        """
        with open(file, 'r+', encoding='utf-8') as f:  # 读取上次未下载成功的文件重新上传
            for linen in f:  # 按行读取文件
                line = linen.replace('\n', '')
                paths = line.split(', ')
                ftp_file_path = paths[0]
                path = paths[1]
                upresult = self.__download_file(ftp,ftp_file_path, path)  # 下载之前下载失败的文件
                if upresult:
                    continue
                else:  # 未下载成功的继续写入下载失败记录
                    f.write(linen)

    def __run(self, ftp, file_path=None, start_dir=None):
        """
        遍历ftp的目录下的所有文件并将文件的详细路径返回
        :param ftp: 一个ftp连接
        :param file_path: 存储返回结果的list
        :param start_path: 目录
        :return:
        """
        if start_dir != None:
            ftp.cwd(start_dir)
        dir_res = []
        ftp.dir('.', dir_res.append)  # 对当前目录进行dir()，将结果放入列表
        for i in dir_res:
            ##判断是否是目录
            if i.startswith("d"):
                # 如是目录回调run（）方法
                self.__run(ftp, file_path, os.path.join(ftp.pwd(),str(i).split(' ')[-1]))
                ftp.cwd('..')
            else:
                # 如不是目录 排除total 0的非目标数据后，将文件全路径加入到返回的list中
                if len(str(i).split(' ')) > 3:
                    file_path.append(ftp.pwd() + "/" + str(i).split(' ')[-1])


    def export_law(self):
        """
        将采集服务器上的pdf文件上传到web服务器上进行数据治理
        :return:
        """
        ftpconn = self.ftpconnect(FTPCONN['host'], FTPCONN['port'], FTPCONN['username'], FTPCONN['password'])
        self.__export_faillaw(ftpconn, 'exportfailed.txt')
        timeNow = datetime.datetime.now()  # 获取当前时间
        timeweekAgo = timeNow - datetime.timedelta(days=7)      # 获取需要处理的目录
        timeweek_ago = str(timeweekAgo.year) + '-' + str(timeweekAgo.month)
        time_now = str(timeNow.year) + '-' + str(timeNow.month)
        # 这里是存储下载法律文件的路径
        if timeweek_ago == time_now:
            FILES_STORES = [r'%s\\%s' % (FILES_DIR, time_now)]
        else:
            FILES_STORES = [r'%s\\%s' % (FILES_DIR, timeweek_ago), r'%s\\%s' % (FILES_DIR, time_now)]
        for FILES_STORE in FILES_STORES:    # 有可能需要上传上月采集的数据
            ftp_dirroot = ftpconn.pwd()    # 获取目标服务器的ftp原始路径
            for root, dirs, files in os.walk(FILES_STORE, topdown=True):
                print("\r正在导出：" + root)
                ftp_path = root[len(FILES_STORE) + 1:]      # 对应的服务器路径
                try:    # 若服务器上文件路径不存在则新建一个文件夹
                    ftpconn.cwd(ftp_path)
                except:
                    ftpconn.mkd(ftp_path)
                ftpconn.cwd(ftp_dirroot)   # 返回目标服务器的ftp原始工作目录
                ftp_file_list = ftpconn.nlst(ftp_path)
                for file in files:
                    path = root + '\\' + file   # 本地文件路径
                    ftp_file_path = ftp_path + '/' + file      # 对应ftp服务器上的文件路径
                    if ftp_file_path in ftp_file_list:
                        continue
                    else:
                        upresult = self.__upload_file(ftpconn,ftp_file_path, path)  # 将文件上传到ftp服务器
                        if upresult:  # 将上传失败的文件写入错误记录
                            continue
                        else:
                            with open('exportfailed.txt', 'a', encoding='utf-8') as f:
                                f.write(ftp_file_path + ', ' + path + '\n')
        self.__export_faillaw(ftpconn, 'exportfailed.txt')
        ftpconn.quit()

    def download_law(self):
        """
        从香港服务器上下载采集的法律数据
        :return:
        """
        ftpconn = self.ftpconnectun(FTPCONN_JW['host'], FTPCONN_JW['port'], FTPCONN_JW['username'], FTPCONN_JW['password']) # 香港服务器FTP被动连接
        self.__export_faillaw(ftpconn, 'downfailed.txt')
        timeNow = datetime.datetime.now()  # 获取当前时间
        timeweekAgo = timeNow - datetime.timedelta(days=7)  # 获取需要处理的目录
        timeweek_ago = str(timeweekAgo.year) + '-' + str(timeweekAgo.month)
        time_now = str(timeNow.year) + '-' + str(timeNow.month)
        # 香港服务器上存储下载法律文件的目录
        if timeweek_ago == time_now:
            FILES_STORES = ['/' + time_now]
        else:
            FILES_STORES = ['/' + timeweek_ago, '/' + time_now]
        for FILES_STORE in FILES_STORES:
            files_list= []
            self.__run(ftpconn, file_path=files_list, start_dir=FILES_STORE)  # 获取目录下所有文件的全路径存到files_list中
            # 从香港服务器上下载文件到采集服务器
            for file_path in files_list:
                file_dir = '/'.join(file_path.split('/')[:-1])  # 香港服务器上文件所在的路径
                file = file_path.split('/')[-1]     # 文件名
                cj_file_dir = r'%s%s' % (FILES_DIR,file_dir)    # 下载到的本地目录
                cj_file_path = os.path.join(cj_file_dir,file)   # 本地pdf文件存放的路径
                if not os.path.exists(cj_file_dir):
                    os.makedirs(cj_file_dir)
                if os.path.exists(cj_file_path):    # 若境外服务器上的文件已经在本地存在，则删除香港服务器上的文件
                    ftpconn.delete(file_path)
                    continue
                # 从香港服务器上下载文件
                downresult = self.__download_file(ftpconn,file_path,cj_file_path)
                if downresult:  # 将下载失败的文件写入错误记录
                    ftpconn.delete(file_path)   # 将下载完毕的文件从香港服务器上删除
                else:
                    with open('downfailed.txt', 'a', encoding='utf-8') as f:
                        f.write(file_path + ', ' + cj_file_path + '\n')
        self.__export_faillaw(ftpconn, 'downfailed.txt')
        ftpconn.quit()


